﻿#include "WebsocektClient.h"
#include "WSListener.h"
#include "../config/SystemConfig.h"
#include "../util/TextUtil.h"
#include "../log/SysLog.h"
#include "../entity/HeartInfo.h"
#include "../entity/BoxInfo.h"

WebsocektClient::WebsocektClient()
	: m_run(true)
	, m_socket(nullptr)
	, m_connected(false)
{
}

WebsocektClient::~WebsocektClient()
{
}

void WebsocektClient::Start()
{
	m_run = true;
	m_thread_msg = std::thread(std::bind(&WebsocektClient::_Connect, this));
	m_thread_heart = std::thread(std::bind(&WebsocektClient::_Heart, this));
}

void WebsocektClient::Stop()
{
	// 停止服务
	m_run = false;
	std::unique_lock<std::mutex> _guard(m_socket_lock);
	if (m_connectionProvider)
	{
		m_connectionProvider->stop();
		m_connectionProvider = nullptr;
	}
	if (m_socket)
	{
		m_socket->stopListening();
		m_socket.reset();
		m_socket = nullptr;
	}

	// 等待退出
	if (m_thread_msg.joinable())
	{
		m_thread_msg.join();
	}
	if (m_thread_heart.joinable())
	{
		m_thread_heart.join();
	}
}

void WebsocektClient::_Connect()
{
	namespace sc = oatpp::websocket;
	namespace sc_client = oatpp::network::tcp::client;

	// 服务连接标志
	m_connected = false;
	while (m_run) {
		// 连接服务器
		if (!m_connected)
		{
			// 未配置socket地址
			std::unique_lock<std::mutex> _guard(m_socket_lock);
			m_socket_url = SystemConfig::get_mutable_instance().GetBoxConf().GetSocketUrl();
			if (m_socket_url.empty())
			{
				std::this_thread::sleep_for(std::chrono::milliseconds(2000));
				continue;
			}

			// 获取套接口端点信息
			std::string ip; int port;
			std::string end_point = TextUtil::get_mutable_instance().GetIpFromWsUrl(m_socket_url, ip, port);
			LOG_WARN("begin connect socket {}", m_socket_url);

			try
			{
				// 创建websocekt连接提供者
				m_connectionProvider = sc_client::ConnectionProvider::createShared({ ip, (v_uint16)port });
				// 创建websocekt链接器
				auto connector = sc::Connector::createShared(m_connectionProvider);
				// 开始连接服务器
				auto connection = connector->connect(end_point);
				// 创建连接套接口
				m_socket = oatpp::websocket::WebSocket::createShared(connection, true);
				// 连接成功
				m_connected = true;
			}
			catch (std::exception& e)
			{
				LOG_WARN("connect socket {} error.", m_socket_url);
				m_connected = false;
			}
			catch (...)
			{
				m_connected = false;
			}
		}

		// 重新连接服务
		if (!m_connected || !m_socket)
		{
			bool exit = false;
			for (int index = 0; index < 2; ++index)
			{
				if (!m_run)
				{
					exit = true;
					break;
				}
				std::this_thread::sleep_for(std::chrono::seconds(1));
			}
			if (exit)
			{
				break;
			}
			continue;
		}

		// 监听服务
		if (m_socket)
		{
			// 盒子信息
			BoxInfo box;
			box.SetId(SystemConfig::get_mutable_instance().GetBoxConf().GetId());
			box.SetIp(SystemConfig::get_mutable_instance().GetLocalConf().GetHttpIp());
			box.SetPort(SystemConfig::get_mutable_instance().GetLocalConf().GetHttpPort());
			std::string json = box.ToJson();

			// 发送连接
			{
				std::lock_guard<std::mutex> lock(m_write_lock);
				m_socket->sendOneFrameText(json);
			}

			// 等待消息
			m_socket->setListener(std::make_shared<WSListener>(m_write_lock));
			m_socket->listen();
			m_connected = false;
		}
	}
}

void WebsocektClient::_Heart()
{
	while (m_run)
	{
		// 未建立连接
		if (!m_connected)
		{
			std::this_thread::sleep_for(std::chrono::seconds(1));
			continue;
		}

		// 连接被修改
		std::string socket_url = SystemConfig::get_mutable_instance().GetBoxConf().GetSocketUrl();
		if (!m_socket_url.empty() && !socket_url.empty() && socket_url != m_socket_url)
		{
			std::unique_lock<std::mutex> _guard(m_socket_lock);
			if (m_socket)
			{
				m_socket->stopListening();
				m_socket.reset();
				m_socket = nullptr;
			}
			m_connected = false;
		}

		// 发送心跳
		HeartInfo heart;
		heart.SetId(SystemConfig::get_mutable_instance().GetBoxConf().GetId());
		heart.SetIp(SystemConfig::get_mutable_instance().GetLocalConf().GetHttpIp());
		heart.SetPort(SystemConfig::get_mutable_instance().GetLocalConf().GetHttpPort());
		std::string json = heart.ToJson();
		{
			std::lock_guard<std::mutex> lock(m_write_lock);
			m_socket->sendOneFrameText(json);
		}

		// 心跳周期30秒
		bool exit = false;
		for (int index = 0; index < 30; ++index)
		{
			if (!m_run)
			{
				exit = true;
				break;
			}
			std::this_thread::sleep_for(std::chrono::seconds(1));
		}
		if (exit)
		{
			break;
		}
	}
}